package design.behavior_strategy;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.function.Function;

/**
 * 策略模式
 * jdk中的策略模式应用 Collections.sort(new ArrayList<Integer>(),(a,b)-> a > b ? 1:0);
 */
public class DemoStrategy {
    public static void main(String[] args) {
        DiscountContext context = new DiscountContext();
        //想要更改折扣计算方式只需要设置对应的策略，不需要修改DiscountContext中的计算逻辑
        context.setDiscountContext(new OverDiscountStrategy());
        BigDecimal total = BigDecimal.valueOf(100);
        System.out.println("原始价格为：" + total + "; 折后价格为：" + context.calculatePrice(BigDecimal.valueOf(100)));


        //演示将策略通过函数的方式进行传入，调用者自己实现策略逻辑
        total = BigDecimal.valueOf(100);
        context.calculatePrice(total, (t -> {
            // 满100减20优惠折扣
            return t.compareTo(BigDecimal.valueOf(100)) >= 0 ? BigDecimal.valueOf(20) : BigDecimal.ZERO;
        }));

        System.out.println("原始价格为：" + total + "; 折后价格为：" + context.calculatePrice(BigDecimal.valueOf(100)));

    }


    //扣点计算上下文类（封装策略，屏蔽高层模块对策略、算法的直接访问，屏蔽可能存在的策略变化)
    public static class DiscountContext {
        /**
         * 默认策略
         */
        private DiscountStrategy strategy = new UserDiscountStrategy();

        /**
         * 可通过该方法重新设置策略覆盖默认策略
         */
        public void setDiscountContext(DiscountStrategy strategy) {
            this.strategy = strategy;
        }

        /**
         * 通过扣点策略计算价格
         */
        public BigDecimal calculatePrice(BigDecimal total) {
            //获取折扣价格
            BigDecimal discountPrice = this.strategy.getDiscount(total);
            //计算折后总价
            total = total.subtract(discountPrice);
            return total;
        }

        /**
         * 将扣点计算策略通过函数的方式传入，不单需要单独定义接口和实现类
         * @param discountStrategy 扣点计算策略
         */
        public BigDecimal calculatePrice(BigDecimal total, Function<BigDecimal,BigDecimal> discountStrategy) {
            //获取折扣价格
            BigDecimal discountPrice = discountStrategy.apply(total);
            //计算折后总价
            total = total.subtract(discountPrice);
            return total;
        }
    }

    /**
     * 扣点策略接口
     */
    public static interface DiscountStrategy {
        BigDecimal getDiscount(BigDecimal total);
    }

    /**
     * 普通会员折扣策略
     */
    public static class UserDiscountStrategy implements DiscountStrategy{
        @Override
        public BigDecimal getDiscount(BigDecimal total) {
            // 普通会员打九折:
            return total.multiply(new BigDecimal("0.1")).setScale(2, RoundingMode.DOWN);
        }
    }

    /**
     * 满减折扣策略
     */
    public static class OverDiscountStrategy implements DiscountStrategy{
        @Override
        public BigDecimal getDiscount(BigDecimal total) {
            // 满100减20优惠:
            return total.compareTo(BigDecimal.valueOf(100)) >= 0 ? BigDecimal.valueOf(20) : BigDecimal.ZERO;
        }
    }

}
